package com.szholly.data.coderule;

import java.util.Set;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.springframework.stereotype.Component;

import com.szholly.utils.spring.SpringBeanFactory;
import com.szholly.utils.util.StringUtils;
import com.szholly.data.coderule.table.*;
import com.szholly.data.general.*;

@Component
public class RuleService {

	// / <summary>
	// / 是否存在参考对象标识
	// / </summary>
	private final static String HAS_REF_ENTITY = "[$REF_ENTITY$]";

	// / <summary>
	// / 执行javascript脚本
	// / </summary>
	// / <param name="script"></param>
	// / <returns></returns>
	public static Object GetSpringValue(String script) {
		try {
			ScriptEngineManager mgr = new ScriptEngineManager();
			ScriptEngine engine = mgr.getEngineByName("JavaScript");

			Object value = engine.eval(script);
			return value;
		} catch (ScriptException e) {
			e.printStackTrace();
			throw new RuntimeException("js脚本错误:" + script);
		}
	}

	// / <summary>
	// / 获取用实体内容替换完的js脚本
	// / </summary>
	// / <param name="entity"></param>
	// / <param name="script"></param>
	// / <returns></returns>
	public static String GetReplaceSpring(RowBase entity, String spring) {
		if (entity == null || StringUtils.IsNullOrSpace(spring))
			return "";

		String strSpring = spring;

		Set<String> keys = entity.keySet();
		for (String key : keys) {
			Object obj = entity.get(key);
			if (null == obj) {
				obj = "";
			}
			String fieldName = "[" + key.toUpperCase() + "]";
			strSpring = strSpring.replace(fieldName, obj.toString());
		}
		return strSpring;
	}

	// / <summary>
	// / 填充编码规则字段
	// / 如果值为空，或引起编码的字段没有发生变化不编码(Entity,GisEntity)
	// / </summary>
	// / <param name="table">ITable</param>
	// / <param name="entity">实体</param>
	public static void FillRuleCode(ITable table, RowBase entity,
			RowBase refEntity) {
		if (table == null || entity == null)
			return;
		Field[] codeRuleFields = table.getCodeRuleFields();
		if (codeRuleFields == null || codeRuleFields.length <= 0)
			return;

		IRule pCode = (IRule) SpringBeanFactory.getBean("RuleClass");
		if (pCode == null)
			return;
		for (Field field : codeRuleFields) {
			Object obj = entity.getValue(GlobalDataType.String,
					field.getFieldName());

			String ruldID = RuleService.GetRuleID(entity,
					field.getCodeRuleExp(), refEntity);

			if (StringUtils.IsNullOrSpace(ruldID))
				continue;
			ruldID = GetRuleInfoID(ruldID);

			if (obj == null || StringUtils.IsNullOrSpace(obj.toString())) {
				String codeRule = pCode.GetCodeRule(ruldID, table, entity,
						refEntity);
				entity.setValue(field.getFieldName(), codeRule);
			} else {
				if (pCode.NeedCodeRule(ruldID, table, entity, refEntity)) {
					String codeRule = pCode.GetCodeRule(ruldID, table, entity,
							refEntity);
					entity.setValue(field.getFieldName(), codeRule);
				}
			}
		}
	}

	// / <summary>
	// / 填充编码规则字段
	// / 无视其他条件强行编码
	// / </summary>
	// / <param name="table">ITable</param>
	// / <param name="entity">实体</param>
	// / <param name="owner">db管理对象</param>
	// / <param name="tvMetadata">表结构信息</param>
	public static void FillRuleCode(ITable table, RowBase entity,
			RowBase refEntity, Boolean beFill) {
		if (table == null || entity == null)
			return;

		Field[] codeRuleFields = table.getCodeRuleFields();
		if (codeRuleFields == null || codeRuleFields.length <= 0)
			return;
		IRule pCode = (IRule) SpringBeanFactory.getBean("RuleClass");
		if (pCode == null)
			return;
		for (Field field : codeRuleFields) {
			Object obj = entity.getValue(GlobalDataType.String,
					field.getFieldName());

			String ruldID = RuleService.GetRuleID(entity,
					field.getCodeRuleExp(), refEntity);
			if (StringUtils.IsNullOrSpace(ruldID))
				continue;
			ruldID = GetRuleInfoID(ruldID);

			if (beFill) {
				String codeRule = pCode.GetCodeRule(ruldID, table, entity,
						refEntity);
				entity.setValue(field.getFieldName(), codeRule);
			} else {
				if (obj == null || StringUtils.IsNullOrSpace(obj.toString())) {
					String codeRule = pCode.GetCodeRule(ruldID, table, entity,
							refEntity);
					entity.setValue(field.getFieldName(), codeRule);
				} else {
					if (pCode.NeedCodeRule(ruldID, table, entity, refEntity)) {
						String codeRule = pCode.GetCodeRule(ruldID, table,
								entity, refEntity);
						entity.setValue(field.getFieldName(), codeRule);
					}
				}
			}
		}
	}

	// / <summary>
	// / 是否需要更新编码
	// / 通过查看编码字段是否发生变化
	// / </summary>
	// / <param name="table"></param>
	// / <param name="entity"></param>
	// / <param name="owner"></param>
	// / <param name="tvMetadata"></param>
	// / <param name="refEntity"></param>
	// / <returns></returns>
	public static Boolean NeedRuleCode(ITable table, RowBase entity,
			RowBase refEntity) {
		if (table == null || entity == null)
			return false;

		Field[] codeRuleFields = table.getCodeRuleFields();
		if (codeRuleFields == null || codeRuleFields.length <= 0)
			return false;
		IRule pCode = (IRule) SpringBeanFactory.getBean("RuleClass");
		if (pCode == null)
			return false;
		for (Field field : codeRuleFields) {
			Object obj = entity.getValue(GlobalDataType.String,
					field.getFieldName());

			String ruldID = RuleService.GetRuleID(entity, field.getCodeRule(),
					refEntity);
			if (StringUtils.IsNullOrSpace(ruldID))
				continue;
			ruldID = GetRuleInfoID(ruldID);

			if (obj == null || StringUtils.IsNullOrSpace(obj.toString()))
				return true;
			else {
				if (pCode.NeedCodeRule(ruldID, table, entity, refEntity))
					return true;
			}
		}

		return false;
	}

	// / <summary>
	// / 根据实体和编码规则脚本获取编码规则ID
	// / </summary>
	// / <param name="entity">数据实体</param>
	// / <param name="codeRuleScript">编码规则获取脚本</param>
	// / <param name="refEntity">参考对象</param>
	// / <returns></returns>
	private static String GetRuleID(RowBase entity, String codeRuleSpring,
			RowBase refEntity) {
		String spring = RuleService.GetReplaceSpring(entity, codeRuleSpring);
		if (StringUtils.IsNullOrSpace(spring))
			return "";

		if (refEntity == null)
			spring = spring.replace(HAS_REF_ENTITY, "false");
		else
			spring = spring.replace(HAS_REF_ENTITY, "true");

		Object value = RuleService.GetSpringValue(spring);
		if (value == null)
			return "";
		else
			return value.toString();
	}

	private static String GetRuleInfoID(String ruleID) {
		String ruleInfoID = "";
		RuleRow row = RuleTable.getSingleRef().GetRowByRuleID(ruleID);
		if (row == null)
			return ruleInfoID;
		ruleInfoID = (String) row.getValue(GlobalDataType.String, "OBJECTID");
		return ruleInfoID;
	}
}